package titt.type;

import java.util.HashMap;

public class Type {

	private final String type_str;
	
	public Type(String type) {
		type_str = type;
	}
	
	public Type(Object o) {
		this(o == null? null : o.getClass());
	}
	
	public Type(Class<?> c) {
		type_str = convert(c).asString();
	}	
	
	
	public boolean isArray() {
		return asString().startsWith(Types.ARRAY_PREFIX);
	}
	
	public boolean isNative() {
		return asString().startsWith(Types.NATIVE_PREFIX);
	}
		
	public Type subtype() {
		if(isArray())
			return new Type(asString().substring(Types.ARRAY_PREFIX.length()));
		if(isNative())
			return new Type(asString().substring(Types.NATIVE_PREFIX.length()));
		return new Type(asString());
	}
	
	public boolean equals(Type t) {
		return t.asString().equalsIgnoreCase(asString());
	}

	@Override
	public boolean equals(Object o) {
		if(!(o instanceof Type)) return false;
		return equals(o);
	}
	
	public boolean equalsAny(Type... t) {
		for(Type a : t) {
			if(equals(a)) return true;
		}
		return false;
	}
	
	public String asString() {
		return type_str;
	}
	
	@Override
	public String toString() {
		return asString();
	}
	
	public Class<?> asClass() {
		if(typeMap.containsKey(asString()))
			return typeMap.get(asString());

		if(isArray())
			try {
				return Class.forName("[" + subtype().asClass().getName());
			}
			catch(Exception e) {}
		
		if(isNative()) 
			try {
				return Class.forName(asString().substring(Types.NATIVE_PREFIX.length()));			
			}
			catch(Exception e) {}
		
		
		return Object.class;
	}

	private Type convert(Class<?> c) {
		
		if(classMap.containsKey(c.getName()))
			return new Type(classMap.get(c.getName()));

		if(c.isArray()) {
			Type sub = convert(c.getComponentType());

			if(sub.isNative())
				return Types.toNative(c);

			return Types.toArray(sub);
		}

		
		return Types.toNative(c);
	}

	
	
	
	
	private static TypeMap typeMap = new TypeMap();
	private static ClassMap classMap = new ClassMap();
	
	
	private static class TypeMap extends HashMap<String, Class<?>> {
		private static final long serialVersionUID = -1L;
		public TypeMap() {
			put("int",		int.class);
			put("boolean",	boolean.class);
			put("char",		char.class);
			put("byte",		byte.class);
			put("short",	short.class);
			put("long",		long.class);
			put("float",	float.class);
			put("double",	double.class);
			put("string",	String.class);
			put("void",		void.class);
			put("unknown",	Object.class);

			put(Types.ARRAY_PREFIX + "int",		int[].class);
			put(Types.ARRAY_PREFIX + "boolean",	boolean[].class);
			put(Types.ARRAY_PREFIX + "char",	char[].class);
			put(Types.ARRAY_PREFIX + "byte",	byte[].class);
			put(Types.ARRAY_PREFIX + "short",	short[].class);
			put(Types.ARRAY_PREFIX + "long",	long[].class);
			put(Types.ARRAY_PREFIX + "float",	float[].class);
			put(Types.ARRAY_PREFIX + "double",	double[].class);
			put(Types.ARRAY_PREFIX + "string",	String[].class);
			put(Types.ARRAY_PREFIX + "unknown",	Object[].class);
		}
	}
	private static class ClassMap extends HashMap<String, String> {
		private static final long serialVersionUID = -1L;

		public ClassMap() {
			put(Integer.class.getName()		, "int");
			put(int.class.getName()			, "int");
			put(Boolean.class.getName()		, "boolean");
			put(boolean.class.getName()		, "boolean");
			put(Character.class.getName()	, "char");
			put(char.class.getName()		, "char");
			put(Short.class.getName()		, "short");
			put(short.class.getName()		, "short");
			put(Long.class.getName()		, "long");
			put(long.class.getName()		, "long");
			put(Float.class.getName()		, "float");
			put(float.class.getName()		, "float");
			put(Double.class.getName()		, "double");
			put(double.class.getName()		, "double");
			put(Byte.class.getName()		, "byte");
			put(byte.class.getName()		, "byte");
			put(String.class.getName()		, "string");
			put(Void.class.getName()		, "void");
			put(void.class.getName()		, "void");
		}
	}
}
